package com.shigen.file.interceptor;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.shigen.file.common.Common;
import com.shigen.file.common.Common.Redis;
import com.shigen.file.config.ConfigProperty;
import com.shigen.file.entity.UserInfo;
import com.shigen.file.exception.BusinessException;
import com.shigen.file.util.IPUtil;
import com.shigen.file.config.TokenUtil;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

/**
 * jwt拦截器
 *
 * @author shigenfu
 */
@Slf4j
@Component
public class JwtInterceptor implements HandlerInterceptor {

  @Resource
  private ConfigProperty configProperty;
  @Resource
  private TokenUtil tokenUtil;
  @Resource
  private StringRedisTemplate stringRedisTemplate;

  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {

    if (!configProperty.isNeedAuthod()) {
      log.warn("ip:{} URL:{} do not need authed", IPUtil.getIp(request), request.getRequestURI());
      return true;
    }

    if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
      return true;
    }

    String token = request.getHeader("token");
    if (StrUtil.isBlank(token)) {
      log.warn("ip:{} URL: {} has no token", IPUtil.getIp(request), request.getRequestURI());
      unAuthorised();
    }
    // 验证token是否过期
    Boolean verify = tokenUtil.verify(token);
    if (!verify) {
      unAuthorised();
    }
    // 获得真实的token，是否在redis中
    String userInfo = stringRedisTemplate.opsForValue().get(Common.Redis.TOKEN_PREFIX + tokenUtil.parseTokenWithTimestamp(token));

    if (StrUtil.isNotEmpty(userInfo)) {
      // 刷新token的有效时长
      refreshToken(token);
      return true;
    }
    unAuthorised();
    return false;
  }

  /**
   * 延长用户信息的保存时长
   */
  public void refreshToken(String token) {
    String parseToken = tokenUtil.parseToken(token);
    String tokenKey = Common.Redis.TOKEN_PREFIX + parseToken.substring(0, parseToken.length() - 10);

    // 获得token的剩余过期时间
    Long expire = stringRedisTemplate.getExpire(tokenKey, TimeUnit.SECONDS);
    if (expire != null && expire < configProperty.getTokenLeftTime()) {
      stringRedisTemplate.expire(tokenKey, configProperty.getTokenTimeOut(), TimeUnit.SECONDS);
      // 获得该token对应的ID
      String userInfoStr = stringRedisTemplate.opsForValue().get(tokenKey);
      UserInfo userInfo = JSON.parseObject(userInfoStr, UserInfo.class);
      String onlineInfoKey = Redis.ONLINE_INFO_PREFIX + userInfo.getUserId();
      stringRedisTemplate.expire(onlineInfoKey, configProperty.getTokenTimeOut(), TimeUnit.SECONDS);
    }
  }

  public void unAuthorised() {
    throw new BusinessException(HttpStatus.UNAUTHORIZED.value(), "未认证");
  }
}
